from distro import id as distro_name
from subprocess import Popen
# subprocess.Popen(["pacman", "--noconfirm", "-S", "vim"]
from sys import exit


"""CONSTANTS"""
# linux distributions that based on ArchLinux
# and used pacman as standart package manager
ARCH_BASED = (
    "arch",
    "manjaro",
)
# to install software we need in name of program,
# path to config, name for command to put this config where
# he must be
TO_INSTALL = {
    "basic": (
        ("vim", "~/",),
        ("fish"),
    ),
    "audio": (
        ("pulseaudio"),
    ),
    "video": (
        ("mpv"),
        ("kdenlive"),
    ),
    "internet": (
        ("firefox"),
        ("telegram-desktop"),
    )
}


"""Configuring basic tools for installing"""
def identify_package_manager():
    """
    identify_package_manager return name of package manager in str
    """
    distro = distro_name()
    if distro in ARCH_BASED:
        return "pacman"
    return exit("I don`t know packager for {}".format(distro))


"""Cli of this script"""
class Cli:
    def __init__(self, software=TO_INSTALL):
        self.software = software
        self.__greeting()
        print(self.__choice_return(self.software))
        self.choice = self.__ask("What would like you to do > ")

    def __greeting(self):
        message = "\n\tWelcome to rice_env script"
        message += "\n\tLet`s install some software\n"
        print(message)
    
    def __detail_sort(self, soft):
        message = ""
        for _ in soft:
            message += "\t\t"
            if (type(_) == tuple) or (type(_) == list):
                message += "Script will install "
                message += "{} to `{}` directory".format(_[0], _[1])
            if type(_) == str:
                message += _
            # add new string when element is not the last
            if soft[-1] != _:
                message += "\n"
        return message

    def __choice_return(self, software, detail="not_detail"):
        """
        ========================= ARGUMENTS ==========================
        detail:
        detail have 2 options(`detail` and `not_detail`)
        `detail` means that software will show all components
        `not_detail` means that software will show only groups such as
        basic, audio, e.t.c.
        """
        message = "\t0. All\n"
        software_keys = tuple(software.keys())
        for i in range(len(software_keys)):
            message += "\t{}. {}\n".format(i+1, software_keys[i].capitalize())

            if detail == "detail":
                soft = software[software_keys[i]]
                message += self.__detail_sort(soft)
                message += "\n"
        return message

    def __ask(self, message):
        try:
            return int(input(message))
        except ValueError:
            print("You could put here only integer numbers".upper())
            return self.__ask(message)
        except KeyboardInterrupt:
            exit()
    
    def __choice_parse(self, choice, software):
        """
        Get from software or TO_INSTALL tuples of name part
        and his content
        """
        # TODO: look at this and try make it better
        parts = [part for part in software]
        if choice == 0:
            part_content = []
            for part in parts:
                for content in software[part]:
                    part_content.append(content)
            return part_content
        else:
            part = parts[choice-1]
            part_content = software[part]
            return part, part_content
    
    def choose_choice(self):
        if self.choice == 0:
            message = "\n\tYou will install:\n"
            message += self.__choice_return(software=TO_INSTALL,
                                           detail="detail")
            print(message)
            return self.__choice_parse(self.choice, self.software)

        # 1. basic, 2. audio, etc
        range_of_selection = [i+1 for i in range(len(self.software))]
        if self.choice in range_of_selection:
            part, content = self.__choice_parse(self.choice, self.software)
            message = "\nFrom {} you will install:\n".format(part.capitalize())
            for i in content:
                message += "\t{}\n".format(i)
            print(message)
            return content

        if (self.choice != 0) and (self.choice not in range_of_selection):
            print("You can`t put numbers out of range\n".upper())
            print(self.__choice_return(self.software))
            self.choice = self.__ask("What would like you to do > ")
            self.choose_choice()


"""Execute manipulation for instalation software"""
class Execute:
    def __init__(self, content, package_manager):
        self.content = content
        self.pkm = package_manager
        self.command = self.__identify_text_command()
        self.__execution()
    
    def __identify_text_command(self):
        """
        In other package managers other commands are used
        Task thin function identify what the command used in
        corrent package manager
        """
        pkms = {
            "pacman": ["pacman", "--noconfirm", "-S"]
        }
        # return key of package manager
        # it needs for checking
        if self.pkm in pkms.keys():
            return pkms[self.pkm]
        if self.pkm not in pkms.keys():
            message = "Command for package manager not found go to "
            message += "to rice.py script and add commands for "
            message += "your package manager"
            print(message.upper())
        
    def __execution(self):
        for soft in self.content:
            command = self.command[:]
            if type(soft) == tuple:
                command.append(soft[0])
            if type(soft) == str:
                command.append(soft)
            print(command)


if __name__ == "__main__":
    package_manager = identify_package_manager()
    content = Cli().choose_choice()
    Execute(
        content=content,
        package_manager=package_manager,
    )
